<template>
  <div class="flow-select">
    <el-select
      :model-value="modelValue"
      style="width: 100%"
      :multiple="true"
      :disabled="disabled"
      :size="size"
      :clearable="clearable"
      :collapse-tags="collapseTags"
      :placeholder="placeholder"
      :teleported="false"
      popper-class="flow-select-popper"
      @visible-change="onVisibleChange"
      @remove-tag="onRemoveTag"
      @clear="onClear"
      @blur="() => emit('blur')"
      @focus="() => emit('focus')"
    >
      <el-option
        v-for="item in selectedItems"
        :key="item[props.value]"
        :label="item[props.label]"
        :value="item[props.value]"
      />
    </el-select>
  </div>
</template>

<script setup lang="ts">
import { getUUID } from '@/common/utils';
import { ANY_OBJECT } from '@/types/generic';
import { Dialog } from '@/components/Dialog';
import FlowSelectDlg from './FlowSelectDlg.vue';
import { FlowEntryController } from '@/api/flow';

const emit = defineEmits<{
  'update:modelValue': [string | number | ANY_OBJECT[]];
  change: [string | number | ANY_OBJECT[], string | number | ANY_OBJECT[]];
  blur: [];
  focus: [];
}>();

const pps = withDefaults(
  defineProps<{
    modelValue: string | number | Array<ANY_OBJECT> | undefined;
    size?: '' | 'default' | 'small' | 'large';
    placeholder?: string;
    props?: ANY_OBJECT;
    disabled?: boolean;
    clearable?: boolean;
    collapseTags?: boolean;
  }>(),
  {
    props: () => {
      return {
        label: 'processDefinitionName',
        value: 'processDefinitionKey',
      };
    },
    size: 'default',
    disabled: false,
    clearable: true,
    collapseTags: true,
  },
);

const widgetId = ref(getUUID());
const selectedItems = ref<ANY_OBJECT[]>([]);
const initialLoad = ref(true);
const flowList = ref<ANY_OBJECT[]>([]);

const handlerEditOperate = (items: ANY_OBJECT[]) => {
  selectedItems.value = items || [];
  emitChange(false);
};

const onVisibleChange = (visible: boolean) => {
  if (visible) {
    Dialog.show<ANY_OBJECT[]>(
      '流程选择',
      FlowSelectDlg,
      {
        area: ['1000px', '700px'],
        offset: '100px',
      },
      {
        value: selectedItems.value,
        props: pps.props,
        flowList: flowList.value,
      },
    )
      .then(res => {
        handlerEditOperate(res);
      })
      .catch(e => {
        console.warn(e);
      });
  }
};

const onRemoveTag = (val: ANY_OBJECT) => {
  selectedItems.value = selectedItems.value.filter(item => {
    return item[pps.props.value] !== val;
  });
  emitChange(false);
};

const onClear = () => {
  selectedItems.value = [];
  emitChange(false);
};

const emitChange = (loadData = true) => {
  const values = selectedItems.value.map(item => item[pps.props.value]);
  emit('update:modelValue', values);
  emit('change', values, selectedItems.value);
};

const loadSelectedFlowList = (values: (string | number)[]) => {
  if (!values || values.length === 0) {
    selectedItems.value = [];
    flowList.value = [];
    return;
  }

  const params = {
    flowEntryDtoFilter: {},
  };

  FlowEntryController.listAllByStartFlow(params)
    .then(res => {
      const list = Array.isArray(res.data) ? res.data : res.data?.dataList || [];
      flowList.value = list.map(item => ({
        ...item,
        processDefinitionName: item.processDefinitionName || '',
        processDefinitionKey: item.processDefinitionKey || '',
      }));

      selectedItems.value = values.map(value => {
        const found = flowList.value.find(item => item[pps.props.value] === value);
        return (
          found || {
            [pps.props.value]: value,
            [pps.props.label]: value,
          }
        );
      });
    })
    .catch(e => {
      console.warn(e);
      selectedItems.value = values.map(value => ({
        [pps.props.value]: value,
        [pps.props.label]: value,
      }));
      flowList.value = [];
    });
};

watch(
  () => pps.modelValue,
  newVal => {
    if (!newVal) {
      selectedItems.value = [];
      return;
    }

    if (!Array.isArray(newVal)) {
      selectedItems.value = [];
      return;
    }

    if (initialLoad.value) {
      initialLoad.value = false;
      if (newVal.length > 0 && newVal.every(item => typeof item !== 'object')) {
        loadSelectedFlowList(newVal as (string | number)[]);
      } else {
        selectedItems.value = newVal.map(item => {
          if (typeof item === 'object') {
            return {
              ...item,
              [pps.props.value]: item[pps.props.value] || item,
              [pps.props.label]: item[pps.props.label] || item,
            };
          }
          return {
            [pps.props.value]: item,
            [pps.props.label]: item,
          };
        });
      }
    }
  },
  {
    immediate: true,
  },
);
</script>

<style scoped>
.flow-select :deep(.flow-select-popper) {
  display: none;
}
</style>
